/*
 * ULSF Sagittarius IDA
 * Copyright (C) 2012, John Pritchard, all rights reserved.
 * 
 * This program is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 */
package sagittarius.design;

import sagittarius.Debug;

/**
 * A {@link Section} operates on a {@link Volume} and {@link Model}
 * for the production of (X,Y,Z)+ sets of vertices for {@link Body}
 * {@link sagittarius.Visualization Visualization}.
 * 
 * <p> {@link Volume} and {@link Model} are the objective and two
 * dimensional (polygon path) inputs, respectively, to the {@link
 * Section} operator.  Each {@link Section} also requires a station
 * input, which is a positive real number between zero and {@link
 * sagittarius.Field length} (exclusive: 0 &lt; station &lt; length).
 * </p>
 *
 * <p> The {@link Section} is essentially two dimensional, like the
 * {@link Model} which is exclusively two dimensional.  The {@link
 * Section} produces three dimensional vertices for {@link Body}
 * having one longitudinal coordinate, X.  This vertex set has the two
 * dimensional polygon path order it inherits (verbatum) from {@link
 * Model}.  As a {@link Model}, a {@link Section} is free to
 * manipulate the coordinates in the polygon path, but maintains the
 * polygon path order. </p>
 * 
 * <p> All sections in a volume must produce an identical number of
 * vertices in their polygons. </p>
 * 
 * @see #getVertices3(float)
 */
public abstract class Section
    extends fv3.math.Abstract
{
    /**
     * {@link Section} instance keys for {@link Volume} cache
     */
    public final static class Key
        extends Object
        implements Comparable<Key>
    {

        public final float station;

        public final int hashCode;

        public Key(double station){
            this( (float)station);
        }
        public Key(float station){
            super();
            this.station = station;
            this.hashCode = Float.floatToIntBits(station);
        }
        public Key(Section section){
            this(section.station);
        }


        public int hashCode(){
            return this.hashCode;
        }
        public boolean equals(Object that){
            if (this == that)
                return true;
            else if (that instanceof Key)
                return (this.station == ((Key)that).station);
            else
                return false;
        }
        public int compareTo(Key that){

            if (null == that)
                return 1;
            else if (this.station == that.station)
                return 0;
            else if (this.station < that.station)
                return -1;
            else
                return 1;
        }
    }

    /**
     * Abstract longitudinal coordinate: 0 &lt; station &lt; {@link
     * sagittarius.Field length}
     */
    public final float station;
    /**
     * Section station area
     */
    public final float area;
    /**
     * Section station radius of a circular section
     */
    public final float radius;



    public Section(Volume volume, double station){
        super();
        this.station = (float)station;
        this.radius = (float)volume.radiusForX(station);
        this.area = (float)(Math.PI*Math.pow(this.radius,2.0));

        if (Debug.Geometry){
            System.out.printf("[G/C] section station % 4.2f, radius % 4.2f, area % 4.2f%n",station,this.radius,this.area);
        }
    }


    public abstract Model getModel();

    public float[] getVertices(){
        Model model = this.getModel();

        return model.getVerticesFor(this.area,this.radius);
    }
    /**
     * @return Zero-positive longitudinal coordinate (in zero to length)
     */
    public final float getStation(){
        return this.station;
    }
    /**
     * @return Area for station
     */
    public final float getArea(){
        return this.area;
    }
    /**
     * @return Haack spheroid (ideal) radius for station
     */
    public final float getRadius(){
        return this.radius;
    }
    /**
     * Longitudinal Section in YZ for {@link Visualization} orientation
     * @param Section X coordinate
     * @return Section XYZ vertices
     */
    public final float[] getVertices3(float x){

        final float[] vertices = this.getVertices();

        final int count = (vertices.length>>1);

        float[] xyz = new float[count*3];
        for (int c2 = 0, c3 = 0, count2 = (count<<1); c2 < count2; ){

            xyz[c3++] = x;
            xyz[c3++] = vertices[c2++];
            xyz[c3++] = vertices[c2++];
        }
        return xyz;
    }
    public final boolean isHyperbolic(){

        return this.getModel().isHyperbolic();
    }
    public final boolean isPath(){

        return this.getModel().isPath();
    }
    public final boolean isSectional(){

        return this.getModel().isSectional();
    }
    public final float getHyperbolicSector(){
        Model model = this.getModel();
        if (model.isHyperbolic())
            return ((Model.Hyperbolic)model).getHyperbolicSector();
        else
            throw new Error(model.getClass().getName());
    }
    public final float getHyperbolicSectorRatio(){
        Model model = this.getModel();
        if (model.isHyperbolic())
            return ((Model.Hyperbolic)model).getHyperbolicSectorRatio();
        else
            throw new Error(model.getClass().getName());
    }
}
